home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
gnu
/
gnulib
/
libsrc98.zoo
/
symdir.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-06-24
|
7KB
|
388 lines
/*
* _read_symdir(), _write_symdir(), _free_symdir(): routines for
* reading/writing the special directories used for symbolic links.
* If symbolic links were not set active in UNIXMODE, then theses
* routines are no-ops.
*
* Written by Eric R. Smith and placed in the public domain. Use
* at your own risk.
*/
#include <stdio.h>
#include <osbind.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include "symdir.h"
#ifndef NAME_MAX
# include <limits.h>
#endif
#ifndef _LIB_NAME_MAX
# define _LIB_NAME_MAX NAME_MAX
#endif
/*
* utility routine to provide buffered I/O for _read_symdir()
*/
#define ResetFgetc() Fgetc(-1)
static int Fgetc(fd)
int fd;
{
static unsigned char buf[BUFSIZ], *pos;
static int siz = 0;
if (fd < 0) {
siz = 0; pos = buf; return 0;
}
if (siz == 0) {
siz = Fread(fd, BUFSIZ, buf);
pos = buf;
if (siz <= 0) {
siz = 0; pos = buf; return -1;
}
}
siz--;
return *pos++;
}
/*
* Routines for keeping a cache of recently used symbolic directories.
* The last 8 directories accessed are kept cached; this really helps
* the directory searches in _unx2dos, but does eat some memory.
*
* entries are added to the cache by _free_symdir, and removed if they
* fall off the end, or if they're retrieved by a subsequent _read_symdir.
*
* IMPLICIT ASSUMPTION: the same directory is never open more than once.
*/
#define CACHESIZE 8
static SYMDIR *in_cache;
static
SYMDIR *_cache_lookup(pth)
const char *pth;
{
SYMDIR **prev = &in_cache, *cur = *prev;
while (cur) {
if (!strcmp(cur->s_pth, pth)) {
/* remove from cache */
*prev = cur->s_nxt;
cur->s_nxt = 0;
return cur;
}
prev = &cur->s_nxt; cur = *prev;
}
return 0;
}
static
void
_cache_add(cur)
SYMDIR *cur;
{
SYMDIR *nxt = 0;
SYMENTRY *dir, *old;
int count = 0;
cur->s_nxt = in_cache;
in_cache = cur;
while (cur) {
nxt = cur->s_nxt;
++count;
if (count == CACHESIZE)
cur->s_nxt = 0;
else if (count > CACHESIZE) {
dir = cur->s_dir;
while (dir) {
old = dir;
dir = dir->next;
free(old);
}
free(cur->s_pth);
free(cur);
}
cur = nxt;
}
}
/*
* free a symbolic directory. Note that _unx2dos is expecting the entries
* to be accessible, i.e. it knows that we're caching at least 1 directory.
* If this ever changes, change _unx2dos.
*/
void _free_symdir(dir)
SYMDIR *dir;
{
if (dir)
_cache_add(dir);
}
/*
* read in the symbolic directory corresponding to "path".
* the symdir must be removed from the cache, since it may
* be modified and written back via _write_symdir
*/
SYMDIR *_read_symdir(path)
char *path;
{
char dirname[FILENAME_MAX], tmp[2*FILENAME_MAX], *p;
int fd, c;
SYMENTRY *old, *new;
SYMDIR *dir;
/* check that symbolic links are active */
if (!_lOK) {
errno = EINVAL;
return NULL;
}
strcpy(dirname, path);
strcat(dirname, "\\");
strcat(dirname, _lDIR);
if (dir = _cache_lookup(dirname))
return dir;
ResetFgetc();
fd = Fopen(dirname, 0);
if (fd < 0 && fd != -ENOENT) {
errno = -fd;
return NULL;
}
dir = (SYMDIR *)malloc(sizeof(SYMDIR)+strlen(tmp)+1);
if (dir == NULL) {
errno = ENOMEM;
return dir;
}
dir->s_pth = strdup(dirname);
if (!dir->s_pth)
return NULL;
dir->s_nxt = 0;
old = NULL;
if (fd == -ENOENT) goto done_directory;
p = tmp;
while ( (c = Fgetc(fd)) >= 0 ) {
if (c == '\r') continue;
if (c == '\n') {
*p++ = 0;
new= (SYMENTRY *)malloc(sizeof(SYMENTRY)+strlen(tmp)+1);
if (new == 0) break;
strcpy(new->linkname, tmp);
new->linkto = new->linkname;
for (p = new->linkname; *p; p++) {
if (*p == '\t') {
*p++ = 0;
new->linkto = p;
break;
}
}
/*
* Now we should check for any further fields, such as "flags"
* it is very important that we save *all* the characters that were given
* in the flags field, as well as setting the bits we understand.
* That way, programs remain compatible with future versions of the
* standard.
*/
for (;*p;p++) {
if (*p == '\t') {
*p++ = 0;
break;
}
}
new->cflags = p; /* save pointer to flag characters */
new->flags = 0;
for (;*p;p++) {
if (*p == 'A')
new->flags |= SD_AUTO;
}
new->next = old;
old = new;
p = tmp;
}
else
*p++ = c;
}
(void)Fclose(fd);
done_directory:
dir->s_dir = old;
return dir;
}
/*
* write a symbolic directory out onto a path
*/
int _write_symdir(path, dir)
char *path;
SYMDIR *dir;
{
SYMENTRY *new;
int fd, r;
char dirname[FILENAME_MAX];
/* check to see that symbolic links are OK */
if (!_lOK)
return -EINVAL;
strcpy(dirname, path);
strcat(dirname, "\\");
strcat(dirname, _lDIR);
if (dir->s_dir == NULL) {
(void)Fdelete(dirname);
return 0;
}
fd = Fcreate(dirname, 0);
if (fd < 0) {
return fd;
}
for (new = dir->s_dir; new; new = new->next) {
(void)Fwrite(fd, strlen(new->linkname), new->linkname);
(void)Fwrite(fd, 1L, "\t");
(void)Fwrite(fd, strlen(new->linkto), new->linkto);
if (new->cflags[0]) {
(void)Fwrite(fd, 1L, "\t");
(void)Fwrite(fd, strlen(new->cflags), new->cflags);
}
r = Fwrite(fd, 1L, "\n");
if (r <= 0) {
(void)Fclose(fd);
return r;
}
}
(void)Fclose(fd);
return 0;
}
/*
* _symdir_lookup, _make_symlink: utility routines that are needed in
* various places
*/
/*
* return the symbolic directory entry for "name", or NULL if it is not
* found
*/
SYMENTRY *
_symdir_lookup(dir, name)
SYMDIR *dir;
const char *name;
{
SYMENTRY *ent;
if (!dir) return 0;
for (ent = dir->s_dir; ent; ent = ent->next) {
if (!strcmp(ent->linkname, name))
return ent;
}
return 0;
}
/*
* _make_autolink(dosname, source): make an "automatic" symbolic link,
* with name "source", to the file whose full canonical dos pathname is in
* "dosname". Returns 1 if link made, 0 if not. It checks the _lAUTO
* flag, so parent functions don't have to. Parents are responsible
* for dealing with any conflicts with existing files.
*/
int _make_autolink(dosname, source)
char *dosname, *source;
{
char path[FILENAME_MAX], oldname[_LIB_NAME_MAX];
char *s, *p;
SYMDIR *dir;
SYMENTRY *d;
if (!_lAUTO)
return 0;
strcpy(path, dosname);
if ((p = strrchr(path, '\\'))) {
*p++ = 0;
_dos2unx(p, oldname);
} else {
_dos2unx(path, oldname);
path[0] = 0;
}
if (!(dir = _read_symdir(path)))
return 0;
d = (SYMENTRY *)
malloc(sizeof(SYMENTRY)+strlen(source)+strlen(oldname)+4);
if (d == 0) {
errno = ENOMEM;
return -1;
_free_symdir(dir);
}
/*
* now set up the fields; remember to set the character flags (cflags) as well!
*/
strcpy(d->linkname, source);
for (s = d->linkname; *s; s++)
;
++s;
d->linkto = s;
strcpy(s, oldname);
for (; *s; s++)
;
++s;
strcpy(s, "A"); /* AUTO flag */
d->cflags = s;
d->flags = SD_AUTO;
d->next = dir->s_dir;
dir->s_dir = d;
_write_symdir(path, dir);
return 1;
}
static
void
_del_dir(cur)
SYMDIR *cur;
{
SYMENTRY *dir, *old;
dir = cur->s_dir;
while (dir) {
old = dir;
dir = dir->next;
free(old);
}
free(cur->s_pth);
free(cur);
}
void
_del_symdir_cache()
{
SYMDIR *cur = in_cache, *nxt = 0;
while (cur) {
nxt = cur->s_nxt;
_del_dir(cur);
cur = nxt;
}
in_cache = 0;
}